﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Xml;
using C4F.DevKit.Telephony.Properties;

namespace C4F.DevKit.Telephony
{

    /// <summary>
    /// This class provides logging functionality in xml file.
    /// </summary>
    public class TapiCallEventLog : TraceListener
    {

        #region Globals

        /// <summary>
        /// Required for holding xmlfile
        /// </summary>
        private XmlDocument xmlDoc;

        /// <summary>
        /// Points to "TraceOutput" node of log file.
        /// </summary>
        private XmlNode parent;

        /// <summary>
        /// Holds path of the xmlfile. 
        /// </summary>
        private string xPath = null;

        #endregion

        #region Constructors

        /// <summary>
        /// Constructor for TapiCallEventLog
        /// </summary>
        /// <param name="xmlFileName">xml log file name</param>
        public TapiCallEventLog(string xmlFileName)
        {
            xPath = xmlFileName;
        }

        #endregion

        #region Helper Methods

        /// <summary>
        /// Opens the xml file and assigns parent by TraceOutput node.
        /// </summary>
        private void OpenXmlTraceFile()
        {
            xmlDoc = new XmlDocument();
            XmlNode rootNode = null;
            if (!System.IO.File.Exists(xPath))
            {
                rootNode = xmlDoc.CreateNode(XmlNodeType.Element, Resources.LogTraceOutput, string.Empty);
                parent = xmlDoc.AppendChild(rootNode);
            }
            else
            {
                try
                {
                    xmlDoc.Load(xPath);
                    parent = xmlDoc.FirstChild;
                    if (parent.Name != Resources.LogTraceOutput) throw new TapiManagerException();
                }
                catch (Exception exception)
                {
                    throw new TapiManagerException(Resources.LogOpenXmlTraceFileException, exception);
                }
            }
        }

        /// <summary>
        /// Saves the xml log file.
        /// </summary>
        private void SaveXmlTraceFile()
        {
            this.xmlDoc.Save(xPath);
        }

        #endregion

        #region Overrides

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            this.Dispose();
        }

        /// <summary>
        /// Overriden method for Trace.Write(string message)
        /// </summary>
        /// <param name="message">A message tio write.</param>
        public override void Write(string message)
        {
            try
            {
                this.OpenXmlTraceFile();
                XmlNode parentNode = AddNode(parent, Resources.LogCallLog, string.Empty);
                this.MakeLogOfMessage(parentNode, message);
                this.SaveXmlTraceFile();
            }
            catch (Exception exception)
            {
                throw new TapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Overriden method for Trace.Write(Object obj)
        /// </summary>
        /// <param name="obj">Object whose information to be looged.</param>
        public override void Write(Object obj)
        {
            try
            {
                this.OpenXmlTraceFile();
                CallInfo entry = (CallInfo)obj;
                XmlNode parentNode = AddNode(parent, Resources.LogCallLog, string.Empty);
                this.MakeLogOfCallInfo(parentNode, entry);
                this.SaveXmlTraceFile();
            }
            catch (Exception exception)
            {
                throw new TapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Overriden method for Trace.Write(Object obj, string category)
        /// </summary>
        /// <param name="obj">Object whose information to be looged.</param>
        /// <param name="message">A category name to write.</param>
        public override void Write(object obj, string category)
        {
            try
            {
                this.OpenXmlTraceFile();
                CallInfo entry = (CallInfo)obj;
                XmlNode parentNode = AddNode(parent, Resources.LogCallLog, string.Empty);
                this.MakeLogOfCallInfo(parentNode, entry);
                this.MakeLogOfCategory(parentNode, category);
                this.SaveXmlTraceFile();
            }
            catch (Exception exception)
            {
                throw new TapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Overriden method for Trace.Write(string message, string category)
        /// </summary>
        /// <param name="message">A message to write.</param>
        /// <param name="category">A category name to write.</param>
        public override void Write(string message, string category)
        {
            try
            {
                this.OpenXmlTraceFile();
                XmlNode parentNode = AddNode(parent, Resources.LogCallLog, string.Empty);
                this.MakeLogOfMessage(parentNode, message);
                this.MakeLogOfCategory(parentNode, category);
                this.SaveXmlTraceFile();
            }
            catch (Exception exception)
            {
                throw new TapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Overriden method for Trace.WriteLine(string message)
        /// </summary>
        /// <param name="message">A message tio write.</param>
        public override void WriteLine(string message)
        {
            try
            {
                this.OpenXmlTraceFile();
                XmlNode parentNode = AddNode(parent, Resources.LogCallLog, string.Empty);
                this.MakeLogOfMessage(parentNode, message);
                this.SaveXmlTraceFile();
            }
            catch (Exception exception)
            {
                throw new TapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Overriden method for Trace.WriteLine(string message, string category)
        /// </summary>
        /// <param name="message">A message to write.</param>
        /// <param name="category">A category name to write.</param>
        public override void WriteLine(string message, string category)
        {
            try
            {
                this.OpenXmlTraceFile();
                XmlNode parentNode = AddNode(parent, Resources.LogCallLog, string.Empty);
                this.MakeLogOfMessage(parentNode, message);
                this.MakeLogOfCategory(parentNode, category);
                this.SaveXmlTraceFile();
            }
            catch (Exception exception)
            {
                throw new TapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Overriden method for Trace.WriteLine(Object obj)
        /// </summary>
        /// <param name="obj">Object whose information to be looged.</param>
        public override void WriteLine(object obj)
        {
            try
            {
                this.OpenXmlTraceFile();
                CallInfo entry = (CallInfo)obj;
                XmlNode parentNode = AddNode(parent, Resources.LogCallLog, string.Empty);
                this.MakeLogOfCallInfo(parentNode, entry);
                this.SaveXmlTraceFile();
            }
            catch (Exception exception)
            {
                throw new TapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Overriden method for Trace.WriteLine(Object obj, string category)
        /// </summary>
        /// <param name="obj">Object whose information to be looged.</param>
        /// <param name="message">A category name to write.</param>
        public override void WriteLine(object obj, string category)
        {
            try
            {
                this.OpenXmlTraceFile();
                CallInfo entry = (CallInfo)obj;
                XmlNode parentNode = AddNode(parent, Resources.LogCallLog, string.Empty);
                this.MakeLogOfCallInfo(parentNode, entry);
                this.MakeLogOfCategory(parentNode, category);
                this.SaveXmlTraceFile();
            }
            catch (Exception exception)
            {
                throw new TapiManagerException(exception.Message, exception);
            }
        }

        #endregion

        #region Logging Methods

        /// <summary>
        /// Logs the call information into CallEventLog node of xml log file.
        /// </summary>
        /// <param name="parentNode">CallEventLog node</param>
        /// <param name="entry">Call to be logged</param>
        private void MakeLogOfCallInfo(XmlNode parentNode, CallInfo entry)
        {
            this.AddNode(parentNode, Resources.LogCallInitiateTime, entry.CallInitiateTime.ToString());
            this.AddNode(parentNode, Resources.LogStartTime, entry.StartTime.ToString());
            this.AddNode(parentNode, Resources.LogEndTime, entry.EndTime.ToString());
            this.AddNode(parentNode, Resources.LogCallerId, entry.CallerId);
            this.AddNode(parentNode, Resources.LogCalledId, entry.CalledId);
            this.AddNode(parentNode, Resources.LogCallDirection, entry.CallDirection.ToString());
            this.AddNode(parentNode, Resources.LogStatus, entry.CallState.ToString());
            this.AddNode(parentNode, Resources.LogLineName, entry.LineName);
        }

        /// <summary>
        /// Logs the specific message given into CallEventLog node of xml log file.
        /// </summary>
        /// <param name="parentNode">CallEventLog node</param>
        /// <param name="message">Message to be logged</param>
        private void MakeLogOfMessage(XmlNode parentNode, string message)
        {
            this.AddNode(parentNode, Resources.LogMessage, message);
        }

        /// <summary>
        /// Logs the specific category given into CallEventLog node of xml log file.
        /// </summary>
        /// <param name="parentNode">CallEventLog node</param>
        /// <param name="category">category to be logged</param>
        private void MakeLogOfCategory(XmlNode parentNode, string category)
        {
            this.AddNode(parentNode, Resources.LogCategory, category);
        }

        /// <summary>
        /// Creates and adds the node under parent node provided.
        /// </summary>
        /// <param name="parentNode">Node name under which new node is to be added.</param>
        /// <param name="childNodeName">New node name.</param>
        /// <param name="nodeText">Text for node.</param>
        /// <returns></returns>
        private XmlNode AddNode(XmlNode parentNode, string childNodeName, string nodeText)
        {
            XmlNode childNode = parentNode.OwnerDocument.CreateNode(XmlNodeType.Element, childNodeName, string.Empty);
            childNode.InnerText = nodeText;
            parentNode.AppendChild(childNode);
            return childNode;
        }

        #endregion

    }

}
